; RANDOM functions
;
#include once <mul32.asm>
;
RANDOMIZE:
; Randomize with 32 bit seed in DE HL
; if SEED = 0, calls ROM to take frames as seed
                       ;- PROC
                       ;- LOCAL TAKE_FRAMES
                       ;- LOCAL FRAMES
                       ;- ld a, h
ora z80_l              ;- or l
ora z80_d              ;- or d
ora z80_e              ;- or e
                       ;- jr z, TAKE_FRAMES
                       ;- ld (RANDOM_SEED_LOW), hl
                       ;- ld (RANDOM_SEED_HIGH), de
rts                    ;- ret

TAKE_FRAMES:
; Takes the seed from frames
                       ;- ld hl, (FRAMES)
                       ;- ld (RANDOM_SEED_LOW), hl
                       ;- ld hl, (FRAMES + 2)
                       ;- ld (RANDOM_SEED_HIGH), hl
rts                    ;- ret

FRAMES EQU    23672
                       ;- ENDP

RANDOM_SEED_HIGH EQU RAND+6    ; RANDOM seed, 16 higher bits
RANDOM_SEED_LOW     EQU 23670  ; RANDOM seed, 16 lower bits

RAND:
                       ;- PROC
                       ;- LOCAL RAND_LOOP
                       ;- ld b, 4
RAND_LOOP:
                       ;- ld  hl,(RANDOM_SEED_LOW)   ; xz -> yw
                       ;- ld  de,0C0DEh   ; yw -> zt
                       ;- ld  (RANDOM_SEED_LOW),de  ; x = y, z = w
                       ;- ld  a,e         ; w = w ^ ( w << 3 )
                       ;- add a,a
                       ;- add a,a
                       ;- add a,a
eor z80_e              ;- xor e
                       ;- ld  e,a
                       ;- ld  a,h         ; t = x ^ (x << 1)
                       ;- add a,a
eor z80_h              ;- xor h
                       ;- ld  d,a
                       ;- rra             ; t = t ^ (t >> 1) ^ w
eor z80_d              ;- xor d
eor z80_e              ;- xor e
                       ;- ld  h,l         ; y = z
                       ;- ld  l,a         ; w = t
                       ;- ld  (RANDOM_SEED_HIGH),hl
pha                    ;- push af
php
                       ;- djnz RAND_LOOP
plp                    ;- pop af
pha
plp                    ;- pop af
pha
lda z80_a              ;- ld d,a
sta z80_d
plp                    ;- pop af
pha
lda z80_a              ;- ld e,a
sta z80_e
plp                    ;- pop af
pha
lda z80_a              ;- ld h,a
sta z80_h
rts                    ;- ret
                       ;- ENDP

RND:
; Returns a FLOATING point integer
; using RAND as a mantissa
                       ;- PROC
                       ;- LOCAL RND_LOOP
jsr RAND               ;- call RAND
; BC = HL since ZX BASIC uses ED CB A registers for FP
lda z80_h              ;- ld b,h
sta z80_b
lda z80_l              ;- ld c,l
sta z80_c
lda z80_e              ;- ld a,e
sta z80_a
ora z80_d              ;- or d
ora z80_c              ;- or c
ora z80_b              ;- or b
bne *+3                ;- ret z   ; Returns 0 if BC=DE=0
rts

; We already have a random 32 bit mantissa in ED CB
; From 0001h to FFFFh
                       ;- ld l,81h	; Exponent
; At this point we have [0 .. 1) FP number;
; Now we must shift mantissa left until highest bit goes into carry
                       ;- ld a, e ; Use A register for rotating E faster (using RLA instead of RL E)
RND_LOOP:
                       ;- dec l
                       ;- sla b
rol z80_c              ;- rl c
rol z80_d              ;- rl d
                       ;- rla
jcs RND_LOOP           ;- jp nc, RND_LOOP
; Now undo last mantissa left-shift once
                       ;- ccf ; Clears carry to insert a 0 bit back into mantissa -> positive FP number
                       ;- rra
ror z80_d              ;- rr d
ror z80_c              ;- rr c
ror z80_b              ;- rr b
lda z80_a              ;- ld e,a     ; E must have the highest byte
sta z80_e
lda z80_l              ;- ld a,l     ; exponent in A
sta z80_a
rts                    ;- ret
                       ;- ENDP

